home *** CD-ROM | disk | FTP | other *** search
- /*---------------------------------------------------------------------------+
- | get_address.c |
- | |
- | Get the effective address from an FPU instruction. |
- | |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
- | |
- | |
- +---------------------------------------------------------------------------*/
-
- /*---------------------------------------------------------------------------+
- | Note: |
- | The file contains code which accesses user memory. |
- | Emulator static data may change when user memory is accessed, due to |
- | other processes using the emulator while swapping is in progress. |
- +---------------------------------------------------------------------------*/
-
-
- #include <linux/stddef.h>
-
- #include <asm/segment.h>
-
- #include "fpu_system.h"
- #include "exception.h"
- #include "fpu_emu.h"
-
- static int reg_offset[] = {
- offsetof(struct info,___eax),
- offsetof(struct info,___ecx),
- offsetof(struct info,___edx),
- offsetof(struct info,___ebx),
- offsetof(struct info,___esp),
- offsetof(struct info,___ebp),
- offsetof(struct info,___esi),
- offsetof(struct info,___edi)
- };
-
- #define REG_(x) (*(long *)(reg_offset[(x)]+(char *) FPU_info))
-
- static int reg_offset_vm86[] = {
- offsetof(struct info,___cs),
- offsetof(struct info,___vm86_ds),
- offsetof(struct info,___vm86_es),
- offsetof(struct info,___vm86_fs),
- offsetof(struct info,___vm86_gs),
- offsetof(struct info,___ss),
- offsetof(struct info,___vm86_ds)
- };
-
- #define VM86_REG_(x) (*(unsigned short *) \
- (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info))
-
-
- /* Decode the SIB byte. This function assumes mod != 0 */
- static void *sib(int mod, unsigned long *fpu_eip)
- {
- unsigned char ss,index,base;
- long offset;
-
- RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(1);
- base = get_fs_byte((char *) (*fpu_eip)); /* The SIB byte */
- RE_ENTRANT_CHECK_ON;
- (*fpu_eip)++;
- ss = base >> 6;
- index = (base >> 3) & 7;
- base &= 7;
-
- if ((mod == 0) && (base == 5))
- offset = 0; /* No base register */
- else
- offset = REG_(base);
-
- if (index == 4)
- {
- /* No index register */
- /* A non-zero ss is illegal */
- if ( ss )
- EXCEPTION(EX_Invalid);
- }
- else
- {
- offset += (REG_(index)) << ss;
- }
-
- if (mod == 1)
- {
- /* 8 bit signed displacement */
- RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(1);
- offset += (signed char) get_fs_byte((char *) (*fpu_eip));
- RE_ENTRANT_CHECK_ON;
- (*fpu_eip)++;
- }
- else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
- {
- /* 32 bit displacment */
- RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(4);
- offset += (signed) get_fs_long((unsigned long *) (*fpu_eip));
- RE_ENTRANT_CHECK_ON;
- (*fpu_eip) += 4;
- }
-
- return (void *) offset;
- }
-
-
- static unsigned long vm86_segment(unsigned char segment)
- {
- segment--;
- #ifdef PARANOID
- if ( segment > PREFIX_SS_ )
- {
- EXCEPTION(EX_INTERNAL|0x130);
- math_abort(FPU_info,SIGSEGV);
- }
- #endif PARANOID
- return (unsigned long)VM86_REG_(segment) << 4;
- }
-
-
- /*
- MOD R/M byte: MOD == 3 has a special use for the FPU
- SIB byte used iff R/M = 100b
-
- 7 6 5 4 3 2 1 0
- ..... ......... .........
- MOD OPCODE(2) R/M
-
-
- SIB byte
-
- 7 6 5 4 3 2 1 0
- ..... ......... .........
- SS INDEX BASE
-
- */
-
- void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
- fpu_addr_modes addr_modes)
- {
- unsigned char mod;
- long *cpu_reg_ptr;
- int offset = 0; /* Initialized just to stop compiler warnings. */
-
- #ifndef PECULIAR_486
- /* This is a reasonable place to do this */
- FPU_data_selector = FPU_DS;
- #endif PECULIAR_486
-
- /* Memory accessed via the cs selector is write protected
- in 32 bit protected mode. */
- #define FPU_WRITE_BIT 0x10
- if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
- && (addr_modes.override.segment == PREFIX_CS_) )
- {
- math_abort(FPU_info,SIGSEGV);
- }
-
- mod = (FPU_modrm >> 6) & 3;
-
- if (FPU_rm == 4 && mod != 3)
- {
- FPU_data_address = sib(mod, fpu_eip);
- return;
- }
-
- cpu_reg_ptr = & REG_(FPU_rm);
- switch (mod)
- {
- case 0:
- if (FPU_rm == 5)
- {
- /* Special case: disp32 */
- RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(4);
- offset = get_fs_long((unsigned long *) (*fpu_eip));
- (*fpu_eip) += 4;
- RE_ENTRANT_CHECK_ON;
- FPU_data_address = (void *) offset;
- return;
- }
- else
- {
- FPU_data_address = (void *)*cpu_reg_ptr; /* Just return the contents
- of the cpu register */
- return;
- }
- case 1:
- /* 8 bit signed displacement */
- RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(1);
- offset = (signed char) get_fs_byte((char *) (*fpu_eip));
- RE_ENTRANT_CHECK_ON;
- (*fpu_eip)++;
- break;
- case 2:
- /* 32 bit displacement */
- RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(4);
- offset = (signed) get_fs_long((unsigned long *) (*fpu_eip));
- (*fpu_eip) += 4;
- RE_ENTRANT_CHECK_ON;
- break;
- case 3:
- /* Not legal for the FPU */
- EXCEPTION(EX_Invalid);
- }
-
- if ( addr_modes.vm86 )
- {
- offset += vm86_segment(addr_modes.override.segment);
- }
-
- FPU_data_address = offset + (char *)*cpu_reg_ptr;
- }
-
-
- void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
- fpu_addr_modes addr_modes)
- {
- unsigned char mod;
- int offset = 0; /* Default used for mod == 0 */
-
- #ifndef PECULIAR_486
- /* This is a reasonable place to do this */
- FPU_data_selector = FPU_DS;
- #endif PECULIAR_486
-
- /* Memory accessed via the cs selector is write protected
- in 32 bit protected mode. */
- #define FPU_WRITE_BIT 0x10
- if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
- && (addr_modes.override.segment == PREFIX_CS_) )
- {
- math_abort(FPU_info,SIGSEGV);
- }
-
- mod = (FPU_modrm >> 6) & 3;
-
- switch (mod)
- {
- case 0:
- if (FPU_rm == 6)
- {
- /* Special case: disp16 */
- RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(2);
- offset = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
- (*fpu_eip) += 2;
- RE_ENTRANT_CHECK_ON;
- goto add_segment;
- }
- break;
- case 1:
- /* 8 bit signed displacement */
- RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(1);
- offset = (signed char) get_fs_byte((signed char *) (*fpu_eip));
- RE_ENTRANT_CHECK_ON;
- (*fpu_eip)++;
- break;
- case 2:
- /* 16 bit displacement */
- RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(2);
- offset = (unsigned) get_fs_word((unsigned short *) (*fpu_eip));
- (*fpu_eip) += 2;
- RE_ENTRANT_CHECK_ON;
- break;
- case 3:
- /* Not legal for the FPU */
- EXCEPTION(EX_Invalid);
- break;
- }
- switch ( FPU_rm )
- {
- case 0:
- offset += FPU_info->___ebx + FPU_info->___esi;
- break;
- case 1:
- offset += FPU_info->___ebx + FPU_info->___edi;
- break;
- case 2:
- offset += FPU_info->___ebp + FPU_info->___esi;
- if ( addr_modes.override.segment == PREFIX_DEFAULT )
- addr_modes.override.segment = PREFIX_SS_;
- break;
- case 3:
- offset += FPU_info->___ebp + FPU_info->___edi;
- if ( addr_modes.override.segment == PREFIX_DEFAULT )
- addr_modes.override.segment = PREFIX_SS_;
- break;
- case 4:
- offset += FPU_info->___esi;
- break;
- case 5:
- offset += FPU_info->___edi;
- break;
- case 6:
- offset += FPU_info->___ebp;
- if ( addr_modes.override.segment == PREFIX_DEFAULT )
- addr_modes.override.segment = PREFIX_SS_;
- break;
- case 7:
- offset += FPU_info->___ebx;
- break;
- }
-
- add_segment:
- offset &= 0xffff;
-
- if ( addr_modes.vm86 )
- {
- offset += vm86_segment(addr_modes.override.segment);
- }
-
- FPU_data_address = (void *)offset ;
- }
-